#pragma once
#include <sys/epoll.h>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "Common.hpp"
#include "Connection.hpp"
#include "Reactor.hpp"

using namespace LogModule;
class Channel : public Connection
{
public:
    Channel(int fd, Inet_Addr client)
    :_sockfd(fd),
     _client(client)
    {
        //将传入的文件描述符设置为非阻塞
        SetNonBlock(fd);
        //设置文件描述符关心的事件
        SetEvent(EPOLLIN | EPOLLET);
    }
#define SIZE 1024
    //处理读事件
    void Recver() override
    {
        //先定义一个缓冲区用来存放当前读取到的数据
        char buffer[SIZE];
        //因为文件描述符是ET模式所以要一次性将数据全部读完
        while(true)
        {
            
            //清空字符串
            buffer[0] = 0;
            //非阻塞读取
            ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                //读取成功设置结束标记位
                buffer[n] = 0;
                //将读到的数据加入到对象的输入缓冲区中
                _inbuffer += buffer;
            }
            else if(n == 0)
            {
                //对端关闭链接,使用异常进行处理
                Excepter();
                return;
            }
            else
            {
                //recv读取'出错'
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    //已经没有数据可读
                    break;
                }
                else if(errno == EINTR)
                {
                    //读取被打断,继续读取
                    continue;
                }
                else
                {
                    //真的出错了,调用异常处理函数
                    Excepter();
                    return;
                }
            }
        }
        LOG(LogLevel::FATAL) << "成功读取到数据" << _inbuffer;
        //数据读取完成
        if(!_inbuffer.empty())
        {
            LOG(LogLevel::FATAL) << "准备调用匿名函数";
            //接收缓冲区中一定有数据
            _outbuffer += _handler(_inbuffer);
        }

        if(!_outbuffer.empty())
        {
            //如果发送缓冲区不为空直接发送
            Sender();
        }
    }
    void Sender() override
    {
        //发送的数据可能一次发不完,所以我们要循环发送,尽量一次性发完
        while(true)
        {
            //以非阻塞形式进行发送
            ssize_t n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
            if(n > 0)
            {
                //有n个字节的数据发送成功
                _outbuffer.erase(0, n);
                if(_outbuffer.empty())
                {
                    //缓冲区已经没有数据了,是时候退出了
                    break;
                }
            }
            else if(n == 0)
            {
                //对端关闭链接,或本端尝试发送0字节的数据
                break;
            }
            else
            {
                //send可能失败要做具体判断
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    //没有数据可写
                    break;
                }
                else if(errno == EINTR)
                {
                    //发送时间时被硬件打断
                    continue;
                }
                else
                {
                    //真的发送出错,调用异常处理函数
                    Excepter();
                    return;
                }
            }
        }

        if(!_outbuffer.empty())
        {
            //说明发送缓冲区还有数据没发完说明,接收缓冲区已满(将文件描述符的写事件设为关心会自动出发一次等待就绪)
            GetOwner()->EnableReadWrite(_sockfd, true, true);
        }
        else
        {
            //数据发送完毕,不需要关心写事件
            GetOwner()->EnableReadWrite(_sockfd, true, false);
        }
    }
    void Excepter() override
    {

        //任何进入异常函数处理的fd都需要关闭
        GetOwner()->DelConnection(_sockfd);
    }

    int GetFd() override
    {
        return _sockfd;
    }
    ~Channel()
    {

    }
private:
    //文件描述符
    int _sockfd;
    //输入输出缓冲区
    std::string _inbuffer;
    std::string _outbuffer;
    //客户端信息
    Inet_Addr _client;
};